package com.nulldev.util.dataManagement.preferencesAPI.fdf_legacy;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.List;
import java.util.Map;

import com.nulldev.util.JVM.JVM;
import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.VariableAPI.MathUtil;
import com.nulldev.util.VariableAPI.StringsUtil;
import com.nulldev.util.data.Arrays.arrays.FastLists;
import com.nulldev.util.data.Arrays.maps.FastMaps;
import com.nulldev.util.dataManagement.preferencesAPI.PreferenceInterface;
import com.nulldev.util.internal.backport.concurrency9.Maps;
import com.nulldev.util.io.file.FileUtil;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;

public class LegacyFDFPreferences implements PreferenceInterface<Map<String, String>>, Serializable {

	private static final Logger log = LoggerFactory.getLogger();
	private static final long serialVersionUID = -3313647497430676143L;
	private List<String> entries;
	private File f;

	public LegacyFDFPreferences(final File f) throws Exception {
		this.f = f;
		if (f == null) {
			this.entries = FastLists.list();
		} else {
			final String line0 = FileUtil.readFirstLine(f).split("<newline>")[0];
			if (line0.startsWith("<") && line0.endsWith(">")) {
				final String[] dta = line0.substring(1, line0.length() - 1).split(" ");
				if (StringsUtil.isEqualCM(dta, 0, "FDF")) {
					final int level = MathUtil.safeParseInt(dta[1].split("=")[1], 1);
					log.debug("Reading an FDF file with API level '" + level + "'.");
					this.type = FDF_Type.FDF;
				} else if (StringsUtil.isEqualCM(dta, 0, "PCMEC")) {
					final int level = MathUtil.safeParseInt(dta[1].split("=")[1], 1);
					log.debug("Reading an PCMEC file with API level '" + level + "'.");
					this.type = FDF_Type.PCMEC;
				} else if (StringsUtil.isEqualCM(dta, 0, "NMC")) {
					final int level = MathUtil.safeParseInt(dta[1].split("=")[1], 1);
					log.debug("Reading an NMC file with API level '" + level + "'.");
					this.type = FDF_Type.NMC;
				}
				this.entries = ArrayUtils.toArrayListFast(FileUtil.readFileToString(f).split("<newline>"));
			} else {
				throw new UnsupportedOperationException("Unsupported file format!");
			}
		}
	}

	@Override
	public void close() throws IOException {
	}

	@Override
	public Map<String, String> get(final String section) {
		if (!has(section)) {
			return Maps.of();
		}
		final Map<String, String> out = FastMaps.map();
		boolean expectedEOF = false;
		for (int i = 0; i < this.entries.size(); i++) {
			final String dta = this.entries.get(i).replaceAll(JVM.lineSeperator(), "");
			if (dta.startsWith("<") && dta.endsWith(">") && !expectedEOF) {
			} else if (dta.startsWith("</") && dta.endsWith(">") && expectedEOF) {
				expectedEOF = false;
			} else if (dta.startsWith("</") && dta.endsWith(">") && !expectedEOF) {
				throw new UnsupportedOperationException("Incorrectly formatted file! [Error at line " + (i + 1) + "]");
			} else {
				final String[] dtax = dta.split(": ");
				out.put(dtax[0], ArrayUtils.StringArrayUtils.addFrom(dtax, 1));
			}
		}
		return out;
	}

	@Override
	public boolean getAsBoolean(final String key) {
		throw new UnsupportedOperationException("The FDF format does not allow the reading of direct variables.");
	}

	@Override
	public boolean has(final String section) {
		if (this.entries == null || this.entries.isEmpty()) {
			return false;
		}
		final List<String> sections = FastLists.list();
		boolean expectedEOF = false;
		boolean endedWithEOF = false;
		boolean startedSection = false;
		for (int i = 0; i < this.entries.size(); i++) {
			final String dta = this.entries.get(i).replaceAll(JVM.lineSeperator(), "");
			if (dta.startsWith("<") && dta.endsWith(">") && !expectedEOF) {
				endedWithEOF = false;
				expectedEOF = true;
				startedSection = true;
			} else if (dta.startsWith("</") && dta.endsWith(">") && expectedEOF) {
				expectedEOF = false;
				sections.add(StringsUtil.substringBetween(dta, "</", ">"));
				endedWithEOF = true;
				startedSection = false;
			} else if (dta.startsWith("</") && dta.endsWith(">") && !expectedEOF) {
				throw new UnsupportedOperationException("Incorrectly formatted file! [Error at line " + (i + 1) + "]");
			}
		}
		if (startedSection && !endedWithEOF) {
			throw new UnsupportedOperationException("Incorrectly formatted file! [Missing an end section decl.]");
		}
		return sections.contains(section);
	}

	@Override
	public void set(final String key, final Map<String, String> value) {
	}

	@Override
	public void clear() {
		if (this.entries != null)
			this.entries.clear();
	}

	@Override
	public void reset() throws IOException {
		this.clear();
		if (this.f != null) {
			final PrintWriter pw = new PrintWriter(this.f);
			pw.println("<FDF level=1><newline>");
			pw.flush();
			pw.close();
		}
	}

	@Override
	public void sync() {
		if (this.f != null && this.entries.isEmpty()) {
			if (f == null) {
				this.entries = FastLists.list();
			} else {
				try {
					final String line0 = FileUtil.readFirstLine(this.f).split("<newline>")[0];
					if (line0.startsWith("<") && line0.endsWith(">")) {
						final String[] dta = line0.substring(1, line0.length() - 1).split(" ");
						if (StringsUtil.isEqualCM(dta, 0, "FDF")) {
							final int level = MathUtil.safeParseInt(dta[1].split("=")[1], 1);
							log.debug("Reading an FDF file with API level '" + level + "'.");
							this.type = FDF_Type.FDF;
						} else if (StringsUtil.isEqualCM(dta, 0, "PCMEC")) {
							final int level = MathUtil.safeParseInt(dta[1].split("=")[1], 1);
							log.debug("Reading an PCMEC file with API level '" + level + "'.");
							this.type = FDF_Type.PCMEC;
						} else if (StringsUtil.isEqualCM(dta, 0, "NMC")) {
							final int level = MathUtil.safeParseInt(dta[1].split("=")[1], 1);
							log.debug("Reading an NMC file with API level '" + level + "'.");
							this.type = FDF_Type.NMC;
						}
						this.entries = ArrayUtils.toArrayListFast(FileUtil.readFileToString(this.f).split("<newline>"));
					} else {
						throw new UnsupportedOperationException("Unsupported file format!");
					}
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
		} else if (this.f != null) {

		}
	}

	private FDF_Type type = FDF_Type.UNKNOWN;

	public static enum FDF_Type {
		UNKNOWN,
		FDF,
		PCMEC,
		NMC,
	}

	public FDF_Type getType() {
		return this.type;
	}
}
